package com.electromagnetic.industry.software.manage.service.serviceimpl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.electromagnetic.industry.software.common.enums.*;
import com.electromagnetic.industry.software.common.util.UserThreadLocal;
import com.electromagnetic.industry.software.manage.mapper.EdFileInfoMapper;
import com.electromagnetic.industry.software.manage.mapper.RoleMapper;
import com.electromagnetic.industry.software.manage.pojo.models.EdFileInfo;
import com.electromagnetic.industry.software.manage.pojo.models.Role;
import com.electromagnetic.industry.software.manage.pojo.models.RolePermission;
import com.electromagnetic.industry.software.manage.pojo.req.RoleDTO;
import com.electromagnetic.industry.software.manage.pojo.req.RolePageDTO;
import com.electromagnetic.industry.software.manage.pojo.req.RolePermissionDTO;
import com.electromagnetic.industry.software.manage.service.PermissionService;
import com.electromagnetic.industry.software.manage.service.RolePermissionService;
import com.electromagnetic.industry.software.manage.service.RoleService;
import com.electromagnetic.industry.software.manage.service.UserRoleService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.electromagnetic.industry.software.common.cons.ElectromagneticConstants.PRJ_PARENT_ID;

@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RolePermissionService rolePermissionService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private PermissionService permissionService;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private EdFileInfoMapper edFileInfoMapper;

    /**
     * 新建角色
     *
     * @param roleDTO
     * @return
     */
    @Transactional
    @Override
    public Boolean createRole(RoleDTO roleDTO) {

        Assert.isTrue(checkRoleNameUnique(roleDTO), StrFormatter.format("角色名称 {} 已存在", roleDTO.getRoleName()));

        // 创建角色
        Role role = new Role();
        role.newInit();
        role.setRoleName(roleDTO.getRoleName());
        role.setRoleDesc(roleDTO.getRoleDesc());
        this.save(role);

        String roleId = role.getId();

        // 创建权限
        List<RolePermissionDTO> data = roleDTO.getData();
        List<RolePermission> list = flattenTree(data, roleId);
        rolePermissionService.saveBatch(list);

        UserThreadLocal.setSuccessInfo("", roleId, StrFormatter.format("创建了角色 {} ", role.getRoleName()));
        return true;
    }

    /**
     * 更新角色
     *
     * @param roleDTO
     * @return
     */
    @Transactional
    @Override
    public Boolean updateRole(RoleDTO roleDTO) {

        Assert.isTrue(checkRoleNameUnique(roleDTO), StrFormatter.format("角色名称 {} 已存在", roleDTO.getRoleName()));

        // 更新角色信息
        LambdaUpdateWrapper<Role> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Role::getId, roleDTO.getRoleId())
                .set(Role::getRoleName, roleDTO.getRoleName())
                .set(Role::getRoleDesc, roleDTO.getRoleDesc());
        this.update(updateWrapper);
        // 失效角色关联的旧权限
        rolePermissionService.logicRemove(roleDTO.getRoleId(), null);
        // 插入/激活新权限信息
        List<RolePermissionDTO> data = roleDTO.getData();
        List<RolePermission> list = flattenTree(data, roleDTO.getRoleId());
        rolePermissionService.insertOrUpdateNewPermissions(list);

        UserThreadLocal.setSuccessInfo("", roleDTO.getRoleId(), "更新了角色");
        return true;
    }

    /**
     * 删除角色
     *
     * @param roleId
     * @return
     */
    @Transactional
    @Override
    public Boolean deleteRole(String roleId) {

        // 失效角色
        LambdaUpdateWrapper<Role> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Role::getId, roleId)
                .set(Role::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code);
        boolean isUpdated = this.update(updateWrapper);

        if (isUpdated) {
            // 失效角色权限关联表
            rolePermissionService.logicRemove(roleId, null);
            // 失效用户角色关联表
            userRoleService.logicRemove(null, roleId);
        }

        UserThreadLocal.setSuccessInfo("", roleId, "删除了角色");
        return true;
    }

    /**
     * 查看角色
     *
     * @param roleId
     * @return
     */
    @Transactional
    @Override
    public RoleDTO getRole(String roleId) {

        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getId, roleId);
        Role role = this.getOne(queryWrapper);

        RoleDTO roleDTO = new RoleDTO();
        roleDTO.setRoleId(role.getId());
        roleDTO.setRoleName(role.getRoleName());
        roleDTO.setRoleDesc(role.getRoleDesc());

        List<EdFileInfo> infos = getSysAndRepo();

        List<RolePermissionDTO> nodes = new ArrayList<>();
        for (EdFileInfo info : infos) {
            RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
            rolePermissionDTO.setId(info.getId());
            rolePermissionDTO.setParentId(info.getParentId());
            rolePermissionDTO.setFileName(info.getFileName());
            List<String> permissionCodes = permissionService.getPermissionCodes(roleId, info.getId());
            if (!permissionCodes.isEmpty()) {
                Map<String, Boolean> dataAuth = new HashMap<>();
                dataAuth.put("data", true);
                rolePermissionDTO.setDataAuth(dataAuth);
            } else {
                Map<String, Boolean> dataAuth = new HashMap<>();
                dataAuth.put("data", false);
                rolePermissionDTO.setDataAuth(dataAuth);
            }
            rolePermissionDTO.setPermission(permissionService.transToMap(permissionCodes, false));
            nodes.add(rolePermissionDTO);
        }

        roleDTO.setData(buildTree(nodes));
        UserThreadLocal.setSuccessInfo("", roleId, "查询了角色详情");
        return roleDTO;
    }

    /**
     * 通过角色名查看角色
     *
     * @param roleName
     * @return
     */
    @Transactional
    @Override
    public RoleDTO getRoleByName(String roleName) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getRoleName, roleName);
        Role role = this.getOne(queryWrapper);
        UserThreadLocal.setSuccessInfo("", role.getId(), "查询了角色详情");
        return getRole(role.getId());
    }

    /**
     * 查看角色列表
     *
     * @param rolePageDTO
     * @return
     */
    @Transactional
    @Override
    public IPage<RoleDTO> getRoles(RolePageDTO rolePageDTO) {

        // 创建分页对象
        Page<RoleDTO> page = new Page<>(rolePageDTO.getPageIndex(), rolePageDTO.getPageSize());
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("r.effect_flag", EffectFlagEnum.EFFECT.code);
        if (StringUtils.isNotBlank(rolePageDTO.getRoleId())) {
            queryWrapper.eq("r.id", rolePageDTO.getRoleId());
        }
        if (StringUtils.isNotBlank(rolePageDTO.getRoleName())) {
            queryWrapper.eq("r.role_name", rolePageDTO.getRoleName());
        }

        if (StrUtil.isNotEmpty(rolePageDTO.getKeyWord())) {
            queryWrapper.like("r.role_name", rolePageDTO.getKeyWord())
                    .or()
                    .like("r.role_desc", rolePageDTO.getKeyWord());
        }

        IPage<RoleDTO> result = roleMapper.getPageRoleDTO(page, queryWrapper);
        for (RoleDTO roleDTO : result.getRecords()) {
            if (roleDTO.getAllowedActions() != null) {
                String chineseString = Arrays.stream(roleDTO.getAllowedActions().split(",")).map(FilePermission::toDescription).collect(Collectors.joining(","));
                roleDTO.setAllowedActions(chineseString);
            }
        }
        UserThreadLocal.setSuccessInfo("", "", "查询了角色列表");
        return result;
    }

    /**
     * 获取所有角色名
     *
     * @return
     */
    @Transactional
    @Override
    public List<HashMap<String, String>> getAllRoleNames() {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Role::getRoleName).eq(Role::getEffectFlag, EffectFlagEnum.EFFECT.code);
        List<String> roleNames = this.listObjs(queryWrapper).stream().map(Object::toString).toList();
        List<HashMap<String, String>> result = new ArrayList<>();
        for (String roleName : roleNames) {
            HashMap<String, String> map = new HashMap<>();
            map.put("value", roleName);
            map.put("label", roleName);
            result.add(map);
        }
        return result;
    }

    /**
     * 空树
     *
     * @return
     */
    @Transactional
    @Override
    public RoleDTO getRoleTemplate() {
        RoleDTO roleDTO = new RoleDTO();
        List<EdFileInfo> infos = getSysAndRepo();
        List<RolePermissionDTO> nodes = new ArrayList<>();
        for (EdFileInfo info : infos) {
            RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
            rolePermissionDTO.setId(info.getId());
            rolePermissionDTO.setParentId(info.getParentId());
            rolePermissionDTO.setFileName(info.getFileName());
            rolePermissionDTO.setDataOwnCode(info.getDataOwn());
            List<String> permissionCodes = new ArrayList<>();
            Map<String, Boolean> dataAuth = new HashMap<>();
            dataAuth.put("data", false);
            rolePermissionDTO.setDataAuth(dataAuth);

            rolePermissionDTO.setPermission(permissionService.transToMap(permissionCodes, false));
            nodes.add(rolePermissionDTO);
        }
        roleDTO.setData(buildTree(nodes));
        UserThreadLocal.setSuccessInfo("", "", "获取角色配置模版成功");
        return roleDTO;
    }

    /**
     * 校验当前角色名称是否唯一
     *
     * @param roleDTO
     * @return
     */
    private Boolean checkRoleNameUnique(RoleDTO roleDTO) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getRoleName, roleDTO.getRoleName())
                .eq(Role::getEffectFlag, EffectFlagEnum.EFFECT.code);
        Role role = this.getOne(queryWrapper);
        return role == null || role.getId().equals(roleDTO.getRoleId());
    }

    /**
     * 权限层级数据扁平化
     *
     * @param nodes
     * @param roleId
     * @return
     */
    private List<RolePermission> flattenTree(List<RolePermissionDTO> nodes, String roleId) {
        List<RolePermission> flatList = new ArrayList<>();
        for (RolePermissionDTO node : nodes) {
            flattenNode(node, flatList, roleId);
        }
        return flatList;
    }

    private void flattenNode(RolePermissionDTO node, List<RolePermission> flatList, String roleId) {

        node.getPermission().forEach((code, hasPermission) -> {
            if (Boolean.TRUE.equals(hasPermission)) { // 检查权限值是否为 true
                RolePermission rolePermission = new RolePermission();
                rolePermission.newInit();
                rolePermission.setRoleId(roleId);
                rolePermission.setFileId(node.getId());
                rolePermission.setPermissionCode(code);
                flatList.add(rolePermission);
            }
        });

        if (node.getDataAuth().get("data").equals(Boolean.TRUE)) {
            RolePermission rolePermission = new RolePermission();
            rolePermission.newInit();
            rolePermission.setRoleId(roleId);
            rolePermission.setFileId(node.getId());
            rolePermission.setPermissionCode(FilePermission.VIEW.getCode());
            flatList.add(rolePermission);
        }

        // 添加当前节点
        if (node.getChildren() != null && !node.getChildren().isEmpty()) {
            for (RolePermissionDTO child : node.getChildren()) {
                flattenNode(child, flatList, roleId); // 递归处理子节点
            }
        }
    }

    // 构建层级结构
    private List<RolePermissionDTO> buildTree(List<RolePermissionDTO> nodes) {
        // 找到所有的根节点
        List<RolePermissionDTO> rootNodes = nodes.stream()
                .filter(node -> node.getParentId().equals(PRJ_PARENT_ID))
                .toList();

        // 递归设置子节点
        for (RolePermissionDTO rootNode : rootNodes) {
            rootNode.setChildren(findChildren(rootNode, nodes));
        }

        return rootNodes;
    }

    // 递归查找子节点
    private List<RolePermissionDTO> findChildren(RolePermissionDTO parent, List<RolePermissionDTO> nodes) {
        return nodes.stream()
                .filter(node -> parent.getId().equals(node.getParentId())) // 匹配父子关系
                .peek(node -> node.setChildren(findChildren(node, nodes))) // 递归设置子节点
                .toList();
    }

    /**
     * 获取层级树结构
     *
     * @return
     */
    private List<EdFileInfo> getFiles(int dataOwnCode) {
        return edFileInfoMapper.selectList(Wrappers.lambdaQuery(EdFileInfo.class)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .eq(EdFileInfo::getDataType, EleDataTypeEnum.FOLDER.code)
                .eq(EdFileInfo::getDataOwn, dataOwnCode)
                .and(wrapper -> wrapper.eq(EdFileInfo::getDataStatus, EleDataStatusEnum.PUBLISHED.code)
                        .or()
                        .eq(EdFileInfo::getDataStatus, EleDataStatusEnum.WAIT_DELETED.code)));
    }

    /**
     * 获取系统层级和库层级
     *
     * @return
     */
    private List<EdFileInfo> getSysAndRepo() {
        List<EdFileInfo> sysInfos = getFiles(DataOwnEnum.SYS_PRJ.code);
        List<EdFileInfo> repoInfos = getFiles(DataOwnEnum.REPO_PRJ.code);
        List<EdFileInfo> infos = new ArrayList<>(sysInfos);
        infos.addAll(repoInfos);
        return infos;
    }

}

